package com.qdlc.p2p.biz.service.borrow.impl;

import java.io.File;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.qdlc.p2p.biz.core.tender.BorrowStrategyContextFactory;
import com.qdlc.p2p.biz.service.RateInterestService;
import com.qdlc.p2p.biz.service.borrow.BorrowFullVerifyService;
import com.qdlc.p2p.biz.util.HclientFileUtil;
import com.qdlc.p2p.biz.util.NoticeTemplateSender;
import com.qdlc.p2p.common.constant.BorrowStatus;
import com.qdlc.p2p.common.constant.BorrowTenderStatus;
import com.qdlc.p2p.common.constant.BorrowUploadType;
import com.qdlc.p2p.common.constant.LogTplNid;
import com.qdlc.p2p.common.constant.VerifyLogType;
import com.qdlc.p2p.common.constant.VerifyResult;
import com.qdlc.p2p.common.constant.VerifyType;
import com.qdlc.p2p.common.exception.BorrowException;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.CollectionUtils;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.common.util.StringUtil;
import com.qdlc.p2p.common.util.UploadFileUtil;
import com.qdlc.p2p.dal.dao.BorrowDao;
import com.qdlc.p2p.dal.dao.BorrowTenderDao;
import com.qdlc.p2p.dal.dao.BorrowUploadDao;
import com.qdlc.p2p.dal.dao.VerifyLogDao;
import com.qdlc.p2p.dal.dto.Borrow;
import com.qdlc.p2p.dal.dto.BorrowTender;
import com.qdlc.p2p.dal.dto.BorrowUpload;
import com.qdlc.p2p.dal.dto.Operator;
import com.qdlc.p2p.dal.dto.User;
import com.qdlc.p2p.dal.dto.VerifyLog;
import com.qdlc.p2p.dal.model.BorrowModel;

/**
 * Created by zhaokaiju on 16/2/18.
 * 满标审核
 */
@Service("borrowFullVerifyService")
public class BorrowFullVerifyServiceImpl implements BorrowFullVerifyService {

	public final static Logger log = Logger.getLogger(BorrowFullVerifyServiceImpl.class);

	@Resource
	private BorrowDao borrowDao;

	@Resource
	private BorrowTenderDao borrowTenderDao;

	@Resource
	private VerifyLogDao verifyLogDao;

	@Resource
	private BorrowUploadDao borrowUploadDao;

	@Resource
	private RateInterestService rateInterestService;

	@Override
	public void verifyFull(BorrowModel borrowModel, Operator operator, File file) {
		long borrowId = borrowModel.getId();
		Borrow borrow = borrowDao.find(borrowId);
		if (null == borrow) {
			log.error("满标复审,该标已不存在于该系统中,borrowId:" + borrowId);
			throw new BorrowException("满标复审,该标已不存在于该系统中!", BorrowException.TYPE_JSON);
		}

        // 待处理的总金额(回调未完成)
        double treatTenderTotal = borrowTenderDao.getBorrowTenderSum(borrowId, BorrowTenderStatus.TREAT);
        if (treatTenderTotal > 0) {
            log.error("第三方还存在未处理投资记录,请耐心等待!borrowId:" + borrowId);
            throw new BorrowException("第三方还存在未处理投资记录,请耐心等待!", BorrowException.TYPE_JSON);
        } else {
            // 已投标的总金额
            double tenderTotal = borrowTenderDao.getBorrowTenderSum(borrowId, BorrowTenderStatus.PROCESSED);
            if (borrow.getAccount() != tenderTotal) {
                log.error(MessageFormat.format("未满标或超标! 标ID={0} 标总额:{1} 已投标:{2}", borrowId, borrow.getAccount(), tenderTotal));
                throw new BorrowException("未满标或超标!", BorrowException.TYPE_JSON);
            }
        }

		int borrowStatus = borrowModel.getStatus(); // 标状态
		if (borrowStatus == BorrowStatus.STATUS_PUBLISHING) { // 初审不通过
			log.info("满标复审未通过,将status修改为4,borrowId:" + borrowId);
			borrowDao.updateStatus(borrowId, BorrowStatus.STATUS_RECHECK_PASSLESS,BorrowStatus.STATUS_TRIAL_PASSED);
			// 更新成功后再进行退款业务处理
			verifyFullFail(borrowModel);
		} else { // 初审通过
            log.info("满标复审通过");
            verifyFullSuccess(borrow);
			// 处理上传合同,此处为管理员手动生成的借款合同上传（不是必要条件）
			uploadBorrowContract(file, borrow);
		}

        // 满标复审结果Log保存
        int verifyResult = borrowStatus == BorrowStatus.STATUS_PUBLISHING ? VerifyResult.NOT_PASS : VerifyResult.PASS;
        VerifyLog verifyLog = new VerifyLog(operator, VerifyLogType.BORROW, borrowId,
                VerifyType.RECHECK, verifyResult, borrowModel.getRemark());
        verifyLogDao.save(verifyLog);
    }

    private void verifyFullSuccess(Borrow borrow) {
        BorrowModel borrowModel = BorrowModel.instance(borrow);
        if (BorrowStatus.STATUS_REPAYMENT_START == borrowModel.getStatus()) {
            throw new BorrowException("该借款标正在还款! borrowId: " + borrow.getId(), BorrowException.TYPE_JSON);
        }
        BorrowStrategyContextFactory.getBorrowStrategy(borrowModel.getType()).verifyFullSuccess(borrowModel);
    }

    @Override
    public void verifyFullSuccess(BorrowModel borrowModel) {
        long borrowId = borrowModel.getId();
        verifyFullSuccess(borrowDao.find(borrowId));
    }

	@Override
	public void verifyFullFail(BorrowModel borrowModel) {
		long borrowId = borrowModel.getId();
		Borrow borrow = this.borrowDao.find(borrowId);

		borrowModel = BorrowModel.instance(borrow);
		if (BorrowStatus.STATUS_RECHECK_PASSLESS2 == borrowModel.getStatus()) {
			throw new BorrowException("该借款标满标审核未通过! borrowId: " + borrowId,
					BorrowException.TYPE_JSON);
		}

		BorrowStrategyContextFactory.getBorrowStrategy(borrowModel.getType()).verifyFullFail(borrowModel);

		// 满标复审不通过,处理加息券
		rateInterestService.borrowFailDoRate(borrowId);

		borrowDao.updateStatus(borrowId, BorrowStatus.STATUS_RECHECK_PASSLESS2, BorrowStatus.STATUS_RECHECK_PASSLESS);

		borrowModel.setStatus(BorrowStatus.STATUS_RECHECK_PASSLESS2);
		borrowModel.setRepaymentAccount(0);
		borrowModel.setRepaymentYesAccount(0);
		borrowModel.setRepaymentYesInterest(0);
		borrowModel.setReviewTime(DateUtil.getNow());
		borrowDao.update(borrowModel.prototype());

		sendNotice(borrowModel, LogTplNid.BORROW_FULL_FAIL, LogTplNid.INVEST_FAIL);
	}

	/**
	 * 处理在满标复审时，有上传借款合同时，就将合同上传到服务器上，同时保存借款合同
	 *
	 * @author Kaiju Zhao
	 * @param file 文件
	 * @param borrow 标
	 */
	private void uploadBorrowContract(File file, Borrow borrow) {
		if (null == file) {
			return;
		}
		try {
			// 校验系统中是否已经存在该标手动上传的合同记录，如果存在，就更新之前的记录
			List<BorrowUpload> upList = borrowUploadDao.findByTypeAndBid(borrow.getId(),
					BorrowUploadType.CONTRACT);
            BorrowUpload borrowUpload = CollectionUtils.isNotNullOrEmpty(upList) ? upList.get(0) : new BorrowUpload();
            String url = UploadFileUtil.getMessage("contractUrl"); // 上传路径
			String nid = UploadFileUtil.getMessage("contractNid"); // 上传文件模块
            String retPath = HclientFileUtil.uploadFileMethod(url, nid, file);
            borrowUpload.setPicPath(StringUtil.isBlank(retPath) ? "" : retPath);
            borrowUpload.setType(BorrowUploadType.CONTRACT);
            borrowUpload.setBorrow(borrow);
            borrowUploadDao.save(borrowUpload);
		} catch (Exception e) {
			log.error("BorrowServiceImpl::uploadBorrowContract() 上传借款合同异常!", e);
			throw new BorrowException("上传借款合同异常！", BorrowException.TYPE_JSON);
		}
	}

	@Override
	public void cancelBorrow(BorrowModel borrowModel) {
		long borrowId = borrowModel.getId();
		Borrow borrow = this.borrowDao.find(borrowId);

		borrowModel = BorrowModel.instance(borrow);
		if (BorrowStatus.STATUS_MANAGER_CANCEL2 == borrowModel.getStatus()) {
			throw new BorrowException("借款标的已经撤回并退款了! borrowId: " + borrowId,
					BorrowException.TYPE_JSON);
		}

		BorrowStrategyContextFactory.getBorrowStrategy(borrowModel.getType()).cancelBorrow(borrowModel);

		// 撤回标,处理加息券
		rateInterestService.borrowFailDoRate(borrowId);

		borrowDao.updateStatus(borrowId, BorrowStatus.STATUS_MANAGER_CANCEL2, BorrowStatus.STATUS_MANAGER_CANCEL);

		borrowModel.setStatus(BorrowStatus.STATUS_MANAGER_CANCEL2);
		borrowModel.setRepaymentAccount(0);
		borrowModel.setRepaymentYesAccount(0);
		borrowModel.setRepaymentYesInterest(0);
		borrowModel.setReviewTime(DateUtil.getNow());
		borrowDao.update(borrowModel.prototype());

		sendNotice(borrowModel, LogTplNid.BORROW_CANCEL, LogTplNid.INVEST_FAIL_BORROW_CANCEL);

	}

	/**
	 * 发送消息通知用户
	 *
	 * @param borrowModel
	 * @param noticeTypeNid
	 * @param investNoticeTypeNid
	 * @author Kaiju Zhao
	 */
	private void sendNotice(BorrowModel borrowModel, String noticeTypeNid, String investNoticeTypeNid) {
		// 给借款人发送通知
		User user = borrowModel.getUser();
		NoticeTemplateSender borrowUserNoticeSender = NoticeTemplateSender.newInstance(user, noticeTypeNid);
		borrowUserNoticeSender.addSendData("borrow", borrowModel);
		borrowUserNoticeSender.send();

		// 给投资人发送通知
		List<BorrowTender> tenderList = borrowTenderDao.find(borrowModel.getId(), BorrowTenderStatus.PROCESSED);
		Map<Long, BorrowTender> tenderUserMap = new HashMap<Long, BorrowTender>();
		if (CollectionUtils.isNotNullOrEmpty(tenderList)) {
			for (BorrowTender tender : tenderList) {
				// 同一个投资人只发一条短信
				BorrowTender borrowTender;
				StringBuilder tenderDetails = new StringBuilder();
				long tenderUserId = tender.getUser().getUserId();
				if (tenderUserMap.containsKey(tenderUserId)) {
					borrowTender = tenderUserMap.get(tenderUserId);
					double account = BigDecimalUtil.add(borrowTender.getAccount(), tender.getAccount());
					int tenderCount = borrowTender.getStatus() + 1;
					// 复用status字段保存 投标次数
					borrowTender.setStatus(tenderCount);
					borrowTender.setAccount(account);
					// 复用addIp字段保存详细信息
					tenderDetails.append(borrowTender.getAddIp()).append("、").append(tender.getAccount());
				} else {
					borrowTender = new BorrowTender();
					BeanUtils.copyProperties(tender, borrowTender);
					// 复用status字段保存 投标次数
					borrowTender.setStatus(1);
					tenderDetails.append(tender.getAccount());
				}
				// 复用addIp字段保存详细信息
				borrowTender.setAddIp(tenderDetails.toString());
				tenderUserMap.put(tenderUserId, borrowTender);
			}
		}

		for (Map.Entry<Long, BorrowTender> entry : tenderUserMap.entrySet() ) {
			BorrowTender tender = entry.getValue();
			if (null != tender) {
				NoticeTemplateSender tenderUserNoticeSender = NoticeTemplateSender.newInstance(tender.getUser(), investNoticeTypeNid);
				tenderUserNoticeSender.addSendData("tenderMoney", tender.getAccount());
				// 详细信息
				tenderUserNoticeSender.addSendData("tenderDetails", tender.getAddIp());
				// 投标总次数
				tenderUserNoticeSender.addSendData("tenderCount", tender.getStatus());
				tenderUserNoticeSender.addSendData("borrow", borrowModel);
				tenderUserNoticeSender.send();
			}
		}

	}

}
